package com.hcss.common.shiro;

import com.hcss.common.constant.ConfigConstants;
import com.hcss.common.shiro.session.ShiroRedisSessionDAO;
import com.hcss.common.shiro.session.ShiroSessionListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @描述: Shiro 配置
 * @作者: xuqian
 * @创建日期: 2018-06-25 16:19
 * @公司 浙江鸿程计算机系统有限公司
 */
@Slf4j
@Configuration
public class ShiroConfig {
    private static final String AUTHC = "authc";
    private static final String ANON = "anon";

    @Bean("shiroProperties")
    public ShiroProperties getShiroProperties() {
        return new ShiroProperties();
    }

    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    // 设置cookie
    @Bean
    public Cookie sessionIdCookie(ShiroProperties shiroProperties){
        Cookie sessionIdCookie=new SimpleCookie(shiroProperties.getCookie().getName());
        sessionIdCookie.setMaxAge(shiroProperties.getCookie().getMaxAge());
        sessionIdCookie.setHttpOnly(shiroProperties.getCookie().isHttpOnly());
        return sessionIdCookie;
    }

    @Bean
    public ShiroSessionListener sessionListener() {
        return new ShiroSessionListener();
    }

    @Bean
    public DefaultWebSessionManager sessionManager(Cookie sessionIdCookie,
                                                   ShiroRedisSessionDAO shiroRedisSessionDAO,
                                                   ShiroSessionListener sessionListener,
                                                   ShiroProperties shiroProperties) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(shiroRedisSessionDAO);
        sessionManager.setSessionIdCookie(sessionIdCookie);
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setDeleteInvalidSessions(false);// 默认为true
        sessionManager.setSessionValidationSchedulerEnabled(false);// 是否开启会话验证器任务 默认为true，sessionValidationInterval字段为验证间隔
        sessionManager.setGlobalSessionTimeout(shiroProperties.getDefaultGlobalExpire());

        sessionManager.getSessionListeners().add(sessionListener);
        return sessionManager;
    }

    @Bean
    public LoginRealm loginRealm() {
        LoginRealm loginRealm = new LoginRealm();
        loginRealm.setCachingEnabled(true);
        loginRealm.setAuthenticationCachingEnabled(true);
        return loginRealm;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(LoginRealm loginRealm,
                                                                  SessionManager sessionManager) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setSessionManager(sessionManager);
        dwsm.setRealm(loginRealm);
        return dwsm;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }

    /**
     * 加载shiroFilter权限控制规则
     * @param shiroFilterFactoryBean
     * @param shiroProperties
     */
    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean, ShiroProperties shiroProperties){
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        for (String value : shiroProperties.getAnon()) {// 不要验证
            filterChainDefinitionMap.put(value, ANON);
        }
        for (String value : shiroProperties.getAuthc()) {// 需要验证
            filterChainDefinitionMap.put(value, AUTHC);
        }
        filterChainDefinitionMap.put("/picture/uploadResultPic",ANON);
        filterChainDefinitionMap.put("/**", "loginRedirectFilter");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
                                                            ShiroProperties shiroProperties,
                                                            ConfigConstants configConstants) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new LoginShiroFilterFactoryBean(shiroProperties);
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl(shiroProperties.getLoginUrl());
        shiroFilterFactoryBean.setSuccessUrl(shiroProperties.getSuccessUrl());
        shiroFilterFactoryBean.setUnauthorizedUrl(shiroProperties.getUnauthorizedUrl());

        Map<String, Filter> filtersMap = new LinkedHashMap<>(1);
        filtersMap.put("loginRedirectFilter", new LoginRedirectFilter(shiroProperties, configConstants));
        shiroFilterFactoryBean.setFilters(filtersMap);

        loadShiroFilterChain(shiroFilterFactoryBean, shiroProperties);
        return shiroFilterFactoryBean;
    }
}
